package com.hyt.it.ogt.kq.main.controller.bm;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.exception.annotation.ThrowsAdvice;
import com.hyt.exception.exception.BusinessLogicException;
import com.hyt.it.ogt.kq.common.bm.config.RedisKeyConstant;
import com.hyt.it.ogt.kq.common.bm.utils.Constant;
import com.hyt.it.ogt.kq.common.gov.config.swagger.ApiVersionConstant;
import com.hyt.it.ogt.kq.common.utils.KqStringUtils;
import com.hyt.it.ogt.kq.main.controller.base.BaseController;
import com.hyt.it.ogt.kq.service.bm.mapper.ProjectMapper;
import com.hyt.it.ogt.kq.service.bm.mapper.ProjectSubjectMapper;
import com.hyt.it.ogt.kq.service.bm.model.entity.Project;
import com.hyt.it.ogt.kq.service.bm.model.entity.ProjectSubject;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentProject;
import com.hyt.it.ogt.kq.service.bm.model.entity.StudentSubject;
import com.hyt.it.ogt.kq.service.bm.model.vo.StudentSubjectVo;
import com.hyt.it.ogt.kq.service.bm.model.vo.SubjectVo;
import com.hyt.it.ogt.kq.service.bm.service.IProjectDataDownLoadRecordService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectExamService;
import com.hyt.it.ogt.kq.service.bm.service.IProjectSubjectService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentProjectService;
import com.hyt.it.ogt.kq.service.bm.service.IStudentSubjectService;
import com.hyt.it.ogt.kq.service.gov.api.bm.BmApi;
import com.hyt.log.annotation.Log;
import com.hyt.swagger.ApiVersion;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiOperationSort;
import io.swagger.annotations.ApiSort;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 考生报名科目表 前端控制器
 * </p>
 *
 * @author wangt
 * @since 2020-05-15
 */
@RestController
@Api(tags = "10.考生报名科目接口", value = "考生报名科目接口")
@ApiSort(value = 10)
@RequestMapping("/bm/student-subject")
@Slf4j
public class StudentSubjectController extends BaseController {


    @Resource
    private RedissonClient redissonClient;
    @Resource
    private IStudentSubjectService iStudentSubjectService;
    @Resource
    private ProjectSubjectMapper projectSubjectMapper;
    @Resource
    private IProjectExamService iProjectExamService;
    @Resource
    private BmApi kwGovClient;
    @Resource
    private IStudentProjectService iStudentProjectService;
    @Resource
    private ProjectMapper projectMapper;
    @Resource
    private IProjectDataDownLoadRecordService iProjectDataDownLoadRecordService;
    @Resource
    private IProjectSubjectService iProjectSubjectService;


    @ApiOperation(value = "10.1.1 查看考生报名科目数据", notes = "20000:成功；15005：未查找到考生报名科目数据")
    @ApiOperationSort(value = 1)
    @RequestMapping(value = "/query/{projectId}/{regId}/{status}", method = RequestMethod.GET)
    public ApiResponse<Object> query(@PathVariable String projectId, @PathVariable String regId, String status) {
        List<ProjectSubject> studentInfo = iStudentSubjectService.getSubjectList(projectId, regId, status);
        if (studentInfo != null) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_SUCCESS).data(studentInfo).build();
        } else {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010176).data(studentInfo).build();
        }
    }

    @ApiOperation(value = "10.1.2 考生端： 添加考生报名科目", notes = "20000:成功；15006：添加考生报名科目数据失败")
    @ApiOperationSort(value = 2)
    @ThrowsAdvice(code = 31010177, print = "添加考生报名科目异常")
    @Log(module = "考生报名科目管理", business = "添加考生报名科目")
    @PostMapping(value = "/add")
    public ApiResponse<String> add(@RequestBody SubjectVo subjectVo) {
        return iStudentSubjectService.addStudentSubject(subjectVo);
    }

    @ApiOperation(value = "10.1.3 取消考生报名科目", notes = "20000:成功；15007：删除考生报名科目数据失败")
    @ApiOperationSort(value = 3)
    @Log(module = "考生报名科目管理", business = "取消考生报名科目")
    @PostMapping(value = "/cancel")
    public Object cancel(@RequestBody StudentSubjectVo studentSubjectVo) {
        try {
            String studentId = iStudentSubjectService.getStudentId(studentSubjectVo.getRegId(),
                    studentSubjectVo.getProjectId());
            // 如果缴费成功，不允许退款
            String payStatus = projectSubjectMapper.getPayStatusById(studentId, studentSubjectVo.getSubjectId());
            if ("1".equals(payStatus)) {
                return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010178).data("考生已缴费，不允许取消报名！").build();
            }
            boolean boo = iStudentSubjectService.delete(studentId, studentSubjectVo.getProjectId(), studentSubjectVo.getSubjectId());
            if (boo) {
                //删除时，注意修改StudentProject的审核状态
                List<ProjectSubject> studentInfo = iStudentSubjectService.getSubjectList(studentSubjectVo.getProjectId(), studentSubjectVo.getRegId(), null);
                if (CollUtil.isNotEmpty(studentInfo)) {
                    StudentProject studentProject = iStudentProjectService.getProjectStudent(studentSubjectVo.getProjectId(), studentSubjectVo.getRegId());
                    if (null != studentProject) {
                        studentProject.setIsAudit(studentInfo.get(0).getIsAudit());
                        iStudentProjectService.updateById(studentProject);
                    }
                }
                return ApiResponse.builder().code(Constant.RESPONSE_CODE_SUCCESS).data("取消考生报名成功！").build();
			} else {
				return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010179).data("取消报名失败！").build();
			}
		} catch (Exception e) {
			return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010179).data(e.toString()).build();
		}
	}

    @ApiOperation(value = "10.1.6 批量取消考生报名科目", notes = "20000:成功；15007：删除考生报名科目数据失败")
    @ApiOperationSort(value = 6)
    @Log(module = "考生报名科目管理", business = "批量取消考生报名科目")
    @RequestMapping(value = "/batchCancel", method = RequestMethod.POST)
    public Object batchCancel(@RequestBody StudentSubjectVo studentSubjectVo) {
        try {
            String studentId = iStudentSubjectService.getStudentId(studentSubjectVo.getRegId(),
                    studentSubjectVo.getProjectId());
            if (null != studentSubjectVo.getSubjectIdList()) {
                String[] subjectIdList = studentSubjectVo.getSubjectIdList().split(StrPool.COMMA);
                for (String subjectId : subjectIdList) {
                    // 如果缴费成功，不允许退款
                    String payStatus = projectSubjectMapper.getPayStatusById(studentId, subjectId);
                    if ("1".equals(payStatus)) {
                        return ApiResponse.builder().code(Constant.RESPONSE_CODE_15045).data("考生已缴费，不允许取消报名！").build();
                    }
                    iStudentSubjectService.delete(studentId, studentSubjectVo.getProjectId(), subjectId);
                }
                //删除时，注意修改StudentProject的审核状态
                List<ProjectSubject> studentInfo = iStudentSubjectService.getSubjectList(studentSubjectVo.getProjectId(), studentSubjectVo.getRegId(), null);
                if (CollUtil.isNotEmpty(studentInfo)) {
                    StudentProject studentProject = iStudentProjectService.getProjectStudent(studentSubjectVo.getProjectId(), studentSubjectVo.getRegId());
                    if (null != studentProject) {
                        studentProject.setIsAudit(studentInfo.get(0).getIsAudit());
                        iStudentProjectService.updateById(studentProject);
                    }
                }
                return ApiResponse.builder().code(Constant.RESPONSE_CODE_SUCCESS).data("取消考生报名成功！").build();
            } else {
                return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010113).data("取消报名失败！").build();
            }
        } catch (Exception e) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010113).data(e.toString()).build();
        }
    }

    @ApiOperation(value = "10.1.4 从科目删除考生", notes = "20000:成功；15007：删除考生报名科目数据失败")
    @ApiOperationSort(value = 4)
    @ThrowsAdvice(code = 31101401, print = "删除考生报名科目数据失败")
    @Log(module = "考生报名科目管理", business = "从科目删除考生")
    @PostMapping(value = "/deleteStudentSubject")
    public Object deleteStudentSubject(@RequestBody StudentSubjectVo studentSubjectVo) {
        if (KqStringUtils.isBlank(studentSubjectVo.getStudentId())) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010180).data("未选择考生！").build();
        }
        if (KqStringUtils.isBlank(studentSubjectVo.getProjectId())) {
            return ApiResponse.builder().code(Constant.RESPONSE_CODE_31010181).data("未选择项目！").build();
        }
        if (KqStringUtils.isBlank(studentSubjectVo.getSubjectId())) {
            return ApiResponse.builder().code(31010196).data("未选择科目！").build();
        }
        return iStudentSubjectService.deleteStudentSubject(studentSubjectVo);

    }

    @ApiOperation(value = "10.1.5 报名小程序提交科目")
    @ApiOperationSort(value = 5)
    @ThrowsAdvice(code = 31101501, print = "报名提交科目异常")
    @Log(module = "考生报名科目管理", business = "报名小程序提交科目")
    @PostMapping(value = "/mini/commitStudentSubject")
    public ApiResponse<String> commitStudentSubject(@RequestBody SubjectVo subjectVo) {
        String projectId = subjectVo.getProjectId();
        // 项目信息
        Project project = projectMapper.selectById(projectId);
        if (null == project) {
            return ApiResponse.<String>builder().code(31111101).data("报名项目信息不存在！").build();
        }
        // 科目列表
        if (null == project.getAuditEndTime() && LocalDateTime.now().isAfter(project.getEndTime())) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_15023).data("报名时间已截止").build();
        }
        // 科目列表
        if (null != project.getAuditEndTime() && LocalDateTime.now().isAfter(project.getAuditEndTime())) {
            return ApiResponse.<String>builder().code(Constant.RESPONSE_CODE_15023).data("报名时间已截止").build();
        }
        if (StrUtil.isBlank(subjectVo.getRegId())) {
            BusinessLogicException.throwException(31101505, "无效的考生账号信息", subjectVo);
        }

        // 获取考生报名的分布式锁
        StringBuilder subjectLockKey = new StringBuilder();
        subjectLockKey.append(RedisKeyConstant.STUDENT_COMMIT_SUBJECT);
        subjectLockKey.append(subjectVo.getProjectId());
        subjectLockKey.append(StrPool.COLON);
        subjectLockKey.append(subjectVo.getRegId());

        RLock lock = redissonClient.getLock(subjectLockKey.toString());
        try {
            boolean b = lock.tryLock(RedisKeyConstant.LOCK_TIME, TimeUnit.SECONDS);
            if (b) {
                List<StudentSubject> subjectList = iStudentSubjectService.queryRegSubject(subjectVo.getRegId(), subjectVo.getProjectId());
                ApiResponse<String> apiResponse = iStudentSubjectService.commitStudentSubjectApi(subjectVo, subjectList);
                return apiResponse;
            }
        } catch (InterruptedException e) {
            log.error("Interrupted!", e);
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
        return ApiResponse.<String>builder().code(31101501).data("报名提交科目异常！").build();
    }

    @ApiOperation(value = "10.2.1 查询考生的科目资格")
    @ApiOperationSort(value = 6)
    @ApiVersion(group = ApiVersionConstant.V2_4_10)
    @ThrowsAdvice(code = 31102101, print = "查询考生的科目资格失败")
    @GetMapping(value = "/getQualificationSubject")
    public ApiResponse<List<String>> getQualificationSubject(@RequestParam String projectId) {
        return ApiResponse.<List<String>>builder()
                .code(Constant.RESPONSE_CODE_SUCCESS)
                .data(iStudentSubjectService.getQualificationSubject(projectId, getUserId()))
                .build();
    }
}
